///
/// @Description:     AMapController 设置地图信息
/// @Author:          胡凯
/// @CreateDate:      2020-09-01
/// @Version:         1.0
///
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:meta/meta.dart';
import 'package:o_amap/aMapModule/map/model/show_area_options.dart';
import 'package:o_amap/aMapModule/search/amap_search.dart';
import 'package:o_amap/aMapModule/search/model/geocode_result.dart';

import 'amap_view.dart';
import '../common/latlng.dart';
import 'model/marker_options.dart';
import 'model/my_location_style.dart';
import 'model/polyline_options.dart';
import 'model/ui_settings.dart';

class AMapController {
  final MethodChannel _mapChannel;
  final EventChannel _markerClickedEventChannel;
  final AmapViewState state;

  /// 命名构造器初始化列表
  AMapController.withId(int id, AmapViewState state)
      : _mapChannel = MethodChannel('com.p595263720.com/map$id'),
        _markerClickedEventChannel =
            EventChannel('com.p595263720.com/marker_clicked$id'),
        state = state;

  void dispose() {}

  ///  设置地图模式, 地图模式参照amap_options.dart 中常量
  Future setMapType(int mapType) {
    return _mapChannel.invokeMethod(
      'setMapType',
      {'mapType': mapType},
    );
  }

  /// 设置缩放等级 设置地图最大缩放级别 缩放级别范围为[3, 20],超出范围将按最大级别计算 。
  Future setZoomLevel(int level) {
    return _mapChannel.invokeMethod(
      'setZoomLevel',
      {'zoomLevel': level},
    );
  }

  /// 设置地图中心点 也可设置其它参数  target 经纬度对象 ， zoom 地图等级默认为10 ，tilt 目标可是取悦的倾斜角度 bearing 可是区域指向的方向
  Future setPosition({
    @required LatLng target,
    double zoom = 10,
    double tilt = 0,
    double bearing = 0,
  }) {
    return _mapChannel.invokeMethod(
      'setPosition',
      {
        'target': target.toJsonString(),
        'zoom': zoom,
        'tilt': tilt,
        'bearing': bearing,
      },
    );
  }

  /// 移动到指定LatLng到中心 相对与setPosition 有平移效果
  Future changeLatLng(LatLng target) {
    return _mapChannel.invokeMethod(
      'changeLatLng',
      {'target': target.toJsonString()},
    );
  }

  /// 移动到指定LatLng到中心 相对与setPosition 有平移效果
  Future changeLatLngForCity(String cityName) async {
    try {
      GeocodeResult geocodeResult =
          await AMapSearch().searchGeocode(name: cityName);
      List<GeocodeAddressList> list = geocodeResult?.geocodeAddressList;
      if (list.length > 0) {
        LatLng target = list[0].latLng;
        changeLatLng(target);
      }
    } catch (e) {}
  }

  /// 获取中心点
  Future<LatLng> getCenterLatlng() async {
    String result = await _mapChannel.invokeMethod("getCenterPoint");
    return LatLng.fromJson(json.decode(result));
  }

  /// 设置是否显示室内地图
  Future showIndoorMap(bool enable) {
    return _mapChannel.invokeMethod(
      'showIndoorMap',
      {'showIndoorMap': enable},
    );
  }

  /// 设置地图初始化参数UiSetting
  Future setUiSettings(UiSettings uiSettings) {
    final _uiSettings = jsonEncode(uiSettings.toJson());
    return _mapChannel.invokeMethod(
      'setUiSettings',
      {'uiSettings': _uiSettings},
    );
  }

  /// 设置当前位置小图标
  Future setMyLocationStyle(MyLocationStyle style) {
    final _styleJson =
        jsonEncode(style?.toJson() ?? MyLocationStyle().toJson());
    return _mapChannel.invokeMethod(
      'setMyLocationStyle',
      {'myLocationStyle': _styleJson},
    );
  }

  /// 添加mark
  Future addMarker(MarkerOptions options) async {
    List<Uint8List> iconData;
    if (options.widget != null && options.icon == null) {
      iconData = await state.widgetToImageData([options.widget]);
    }
    String _optionsJson;
    if (iconData != null) {
      _optionsJson = options.toJsonString(widget: iconData[0]);
    } else {
      _optionsJson = options.toJsonString();
    }

    return _mapChannel.invokeMethod(
      'addMarker',
      {'markerOptions': _optionsJson},
    );
  }

  /// 添加marks  是应用与批量添加
  Future addMarkers(List<MarkerOptions> optionsList,
      {bool moveToCenter = true}) async {
    assert(optionsList != null);
    if (optionsList.isEmpty) return Future.value([]);
    List<Widget> widget = List<Widget>(); // 记录widget
    List<int> index = List<int>(); // 记录对应widget 位置
    for (var i = 0; i < optionsList.length; i++) {
      if (optionsList[i].widget != null) {
        widget.add(optionsList[i].widget);
        index.add(i);
      }
    }
    List<Uint8List> list = await this.state.widgetToImageData(widget);
    List<Map<String, Object>> jsonRes = List<Map<String, Object>>();
    for (var j = 0; j < optionsList.length; j++) {
      if (optionsList[j].widget != null &&
          index.indexOf(j) != -1 &&
          index[index.indexOf(j)] == j) {
        //表示存在
        jsonRes.add(optionsList[j].toJson(widget1: list[index.indexOf(j)]));
      } else {
        jsonRes.add(optionsList[j].toJson());
      }
    }
    final _optionsListJson = jsonEncode(jsonRes);
    return _mapChannel.invokeMethod(
      'addMarkers',
      {'moveToCenter': moveToCenter, 'markerOptionsList': _optionsListJson},
    );
  }

  /// 清除可视区域内的所有mark点，参数为true,myLocationOverlay（内置定位覆盖物）除外。
  Future clearMarkers({bool isKeepMyLocationOverlay = true}) {
    return _mapChannel.invokeMethod(
        'clearMarkers', {'isKeepMyLocationOverlay': isKeepMyLocationOverlay});
  }

  /// 从地图上删除所有的覆盖物(marker，circle，polyline 等对象),参数为true,myLocationOverlay（内置定位覆盖物）除外。
  Future clear({bool isKeepMyLocationOverlay = true}) {
    return _mapChannel.invokeMethod(
        'clearMap', {'isKeepMyLocationOverlay': isKeepMyLocationOverlay});
  }

  /// marker点击事件流
  Stream<MarkerOptions> get markerClickedEvent {
    try {
      return _markerClickedEventChannel
          .receiveBroadcastStream()
          .map((data) => MarkerOptions.fromJson(jsonDecode(data)));
    } catch (e) {
      print(e);
    }
  }

  /// 获地图点击
  Stream<LatLng> get mapClickedEvent {
    try {
      return _markerClickedEventChannel
          .receiveBroadcastStream()
          .map((data) => LatLng.fromJson(json.decode(data)));
    } catch (e) {
      print(e);
    }
  }

  /// 添加线
  Future addPolyline(PolylineOptions options) {
    return _mapChannel.invokeMethod(
      'addPolyline',
      {'options': options.toJsonString()},
    );
  }

  /// 设置屏幕上的某个像素点为地图中心点
  Future setPointToCenter(double x, double y) {
    return _mapChannel.invokeMethod(
      'setPointToCenter',
      {'x': x, 'y': y},
    );
  }

  /// 设置最佳显示区域
  Future setShowArea(ShowAreaOptions options) {
    return _mapChannel
        .invokeMethod('setShowArea', {'options': options.toJsonString()});
  }

  //---------------------- 未实现,需要联系作者开发区域(考虑到可能暂时不会使用) ------------------

  // 设置自定义样式的文件路径,需求可以联系Author
  Future setCustomMapStylePath(String path) {
    return _mapChannel.invokeMethod(
      'map#setCustomMapStylePath',
      {'path': path},
    );
  }

  // 使能自定义样式,暂未实现，需求可以联系Author
  Future setMapCustomEnable(bool enabled) {
    return _mapChannel.invokeMethod(
      'map#setMapCustomEnable',
      {'enabled': enabled},
    );
  }

  // 使用在线自定义样式,暂未实现，需求可以联系Author
  Future setCustomMapStyleID(String styleId) {
    return _mapChannel.invokeMethod(
      'map#setCustomMapStyleID',
      {'styleId': styleId},
    );
  }

  // 设置语言，暂未实现，需求可以联系Author
  Future setLanguage(int language) {
    return _mapChannel.invokeMethod(
      'map#setLanguage',
      {'language': language},
    );
  }

  // 移动镜头到当前的视角,需求可以联系Author
  Future zoomToSpan(
    List<LatLng> bound, {
    int padding = 80,
  }) {
    final boundJson =
        jsonEncode(bound?.map((it) => it.toJson())?.toList() ?? List());

    return _mapChannel.invokeMethod(
      'map#zoomToSpan',
      {
        'bound': boundJson,
        'padding': padding,
      },
    );
  }

  // 限制地图的显示范围
  Future setMapStatusLimits({
    /// 西南角 [Android]
    @required LatLng swLatLng,

    /// 东北角 [Android]
    @required LatLng neLatLng,

    /// 中心 [iOS]
    @required LatLng center,

    /// 纬度delta [iOS]
    @required double deltaLat,

    /// 经度delta [iOS]
    @required double deltaLng,
  }) {
    return _mapChannel.invokeMethod(
      'map#setMapStatusLimits',
      {
        'swLatLng': swLatLng.toJsonString(),
        'neLatLng': neLatLng.toJsonString(),
        'center': center.toJsonString(),
        'deltaLat': deltaLat,
        'deltaLng': deltaLng,
      },
    );
  }
}
